//
//  DBDeviceInfoTool.swift
//  DBCA
//
//  Created by mugua on 2024/7/2.
//

import Foundation
import CoreTelephony
import Alamofire
import SystemConfiguration.CaptiveNetwork

class DBDeviceInfoTool {
    
    static func getSystemVersion() -> String {
        return UIDevice.current.systemVersion
    }
    
    static func getAppVersion() -> String {
        return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
    }
    
    static func getDeviceName() -> String {
        return UIDevice.current.name
    }
    
    static func getDeviceLanguage() -> String {
        return NSLocale.preferredLanguages.first ?? "unknown"
    }
    
    static func getBundleId() -> String {
        return Bundle.main.bundleIdentifier ?? ""
    }
    
    static func getDeviceModel() -> String {
        var systemInfo = utsname()
        uname(&systemInfo)
        
        let machine = systemInfo.machine
        var identifier = ""
        let mirror = Mirror(reflecting: machine)
        
        for child in mirror.children {
            let value = child.value
            
            if let value = value as? Int8, value != 0 {
                identifier.append(String(UnicodeScalar(UInt8(value))))
            }
        }
        
        return identifier
    }
    
    static func getTimeZone() -> String {
        var timeZone = NSTimeZone.local.localizedName(for: .shortStandard, locale: NSLocale.system)
        if timeZone == "GMT" {
            timeZone = "GMT+0"
        }
        return timeZone ?? ""
    }
    
    static func getCarrierName() -> String {
        var tempName: String?
        let info = CTTelephonyNetworkInfo()
        if #available(iOS 12.0, *) {
            if let carrierProviders = info.serviceSubscriberCellularProviders {
                for item in carrierProviders.values {
                    if item.mobileCountryCode != nil {
                        tempName = item.carrierName
                    }
                }
            }
        } else {
            if let carrier: CTCarrier = info.subscriberCellularProvider {
                tempName = carrier.carrierName
            }
        }
        
        return tempName ?? ""
    }
    
    static func getChargeLevel() -> Int {
        let device = UIDevice.current
        let wasBatteryMonitoringEnable = device.isBatteryMonitoringEnabled
        device.isBatteryMonitoringEnabled = true
        
        let batteryLevel = Int(round((device.batteryLevel > 0 ? device.batteryLevel : 0) * 100))
        device.isBatteryMonitoringEnabled = wasBatteryMonitoringEnable
        return batteryLevel
    }
    
    static func getIsCharging() -> Int {
        let device = UIDevice.current
        let wasBatteryMonitoringEnable = device.isBatteryMonitoringEnabled
        device.isBatteryMonitoringEnabled = true
        
        var isCharging = 0
        if device.batteryState == .charging ||
            device.batteryState == .full {
            isCharging = 1
        }
        device.isBatteryMonitoringEnabled = wasBatteryMonitoringEnable
        return isCharging
    }
    
    static func getIsUseVpn() -> Int {
        guard let cfDict = CFNetworkCopySystemProxySettings() else {
            return 0
        }
        
        let nsDict = cfDict.takeRetainedValue() as NSDictionary
        
        guard let keys = nsDict["__SCOPED__"] as? [String:Any] else {
            return 0
        }
        
        let keyValues: [String] = [
            "tap",
            "tun",
            "ppp",
            "ipsec",
            "ipsec0",
        ]
        
        var result = 0
        for key in keys.keys {
            keyValues.forEach { (value) in
                if key.contains(value) {
                    result = 1
                }
            }
        }
        
        return result
    }
    
    static func getIsUseProxy() -> Int {
        guard let systemProxyConfig = CFNetworkCopySystemProxySettings()?.takeRetainedValue() else {
            return 0
        }
        
        let proxys = CFNetworkCopyProxiesForURL(URL(string: "http://www.apple.com")! as CFURL, systemProxyConfig).takeRetainedValue() as NSArray
        guard proxys.count > 0 else {
            return 0
        }
        
        guard let proxy = proxys.object(at: 0) as? NSDictionary else {
            return 0
        }
        
        guard let proxyType = proxy.object(forKey: kCFProxyTypeKey) as? String else {
            return 0
        }
        
        if proxyType == "kCFProxyTypeNone" {
            return 0
        }
        
        return 1
    }
    
    static func getNetworkName() -> String {
        if let reachabilityManager = DBNetworkMonitor.shared.reachabilityManager {
            if reachabilityManager.isReachableOnCellular {
                return "4G"
            }
            
            if reachabilityManager.isReachableOnEthernetOrWiFi {
                return "WiFi"
            }
            
            if !reachabilityManager.isReachable {
                return "Bad Network"
            }
        }
        
        return "Unknown Network"
    }
    
    static func getIsIphone() -> Int {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return 1
        }
        
        return 0
    }
    
    static func getIpAddress() -> String? {
        var address: String?
        var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
        guard getifaddrs(&ifaddr) == 0 else {
            return nil
        }
        guard let firstAddr = ifaddr else {
            return nil
        }
        
        for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
            let interface = ifptr.pointee
            let addrFamily = interface.ifa_addr.pointee.sa_family
            if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
                let name = String(cString: interface.ifa_name)
                if name == "en0" {
                    var addr = interface.ifa_addr.pointee
                    var hostName = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    getnameinfo(&addr,socklen_t(interface.ifa_addr.pointee.sa_len), &hostName, socklen_t(hostName.count), nil, socklen_t(0), NI_NUMERICHOST)
                    address = String(cString: hostName)
                }
            }
        }
        
        freeifaddrs(ifaddr)
        return address
    }
    
    static func getWifiName() -> String {
        var wifiName = ""
        let wifiInterfaces = CNCopySupportedInterfaces()
        guard wifiInterfaces != nil else {
            return wifiName
        }
        
        let interfaceArr = CFBridgingRetain(wifiInterfaces) as! [String]
        if interfaceArr.count > 0 {
            let interfaceName = interfaceArr[0] as CFString
            let ussafeInterfaceData = CNCopyCurrentNetworkInfo(interfaceName)
            
            if ussafeInterfaceData != nil {
                let interfaceData = ussafeInterfaceData as! [String: Any]
                wifiName = interfaceData["SSID"]! as! String
            }
        }
        return wifiName
    }
    
    static func getBssid() -> String {
        var bssid = ""
        let wifiInterfaces = CNCopySupportedInterfaces()
        guard wifiInterfaces != nil else {
            return bssid
        }
        
        let interfaceArr = CFBridgingRetain(wifiInterfaces) as! [String]
        if interfaceArr.count > 0 {
            let interfaceName = interfaceArr[0] as CFString
            let ussafeInterfaceData = CNCopyCurrentNetworkInfo(interfaceName)
            
            if ussafeInterfaceData != nil {
                let interfaceData = ussafeInterfaceData as! [String: Any]
                bssid = interfaceData["BSSID"]! as! String
            }
        }
        return bssid
    }
    
    static func getIsSimulator() -> Int {
#if TARGET_IPHONE_SIMULATOR
        return 1
#endif
        return 0
        
    }
    
    static func getIsJailbreak() -> Int {
        
        let jailbreakFilePaths = [
            "/Applications/Cydia.app",
            "/Library/MobileSubstrate/MobileSubstrate.dylib",
            "/bin/bash",
            "/usr/sbin/sshd",
            "/etc/apt",
            "/usr/bin/ssh"
        ]
        
        for path in jailbreakFilePaths {
            if FileManager.default.fileExists(atPath: path) {
                return 1
            }
        }
        
        if let url = URL(string: "cydia://package/com.example.package"), UIApplication.shared.canOpenURL(url) {
            return 1
        }
        
        
        let testString = "Jailbreak Test"
        do {
            try testString.write(toFile: "/private/jailbreakTest.txt", atomically: true, encoding: .utf8)
            
            try FileManager.default.removeItem(atPath: "/private/jailbreakTest.txt")
            return 1
        } catch {
            
        }
        
        return 0
    }
    
    static func getTotalDiskNum() -> Int64 {
        do {
            let fattributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())
            if let space = fattributes[FileAttributeKey.systemSize] as? NSNumber {
                return Int64(truncating: space)
            }
            
        } catch  {
            
        }
        
        return 0
    }
    
    static func getFreeDiskNum() -> Int64 {
        if #available(iOS 11.0, *) {
            if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage {
                return space
            } else {
                return 0
            }
        } else {
            if let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
               let freeSpace = (systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber)?.int64Value {
                return freeSpace
            } else {
                return 0
            }
        }
    }
    
    static func getMemoryTotalNum() -> Int64 {
        let mem = ProcessInfo.processInfo.physicalMemory
        return Int64(mem)
    }
    
    static func getMemoryFreeNum() -> Int64 {
        var vmStats = vm_statistics64()
        var count = mach_msg_type_number_t(MemoryLayout<vm_statistics64_data_t>.stride / MemoryLayout<integer_t>.stride)
        
        let result = withUnsafeMutablePointer(to: &vmStats) {
            $0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
                host_statistics64(mach_host_self(), HOST_VM_INFO64, $0, &count)
            }
        }
        
        guard result == KERN_SUCCESS else {
            return 0
        }
        
        let pageSize = vm_kernel_page_size
        let freeMemory = Int64(vmStats.free_count) * Int64(pageSize)
        return freeMemory
    }
    
    static func DBFormatter(_ bytes: Int64) -> String {
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = ByteCountFormatter.Units.useGB
        formatter.countStyle = ByteCountFormatter.CountStyle.decimal
        formatter.includesUnit = false
        return formatter.string(fromByteCount: bytes) as String
    }
    
    static func getMachineModelName() -> String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        
        switch identifier {
        case "iPhone1,1":                           return "iPhone 1G"
        case "iPhone1,2":                           return "iPhone 3G"
        case "iPhone2,1":                           return "iPhone 3GS"
        case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4"
        case "iPhone4,1":                           return "iPhone 4S"
        case "iPhone5,1", "iPhone5,2":              return "iPhone 5"
        case "iPhone5,3", "iPhone5,4":              return "iPhone 5C"
        case "iPhone6,1", "iPhone6,2":              return "iPhone 5S"
        case "iPhone7,1":                           return "iPhone 6 Plus"
        case "iPhone7,2":                           return "iPhone 6"
        case "iPhone8,1":                           return "iPhone 6s"
        case "iPhone8,2":                           return "iPhone 6s Plus"
        case "iPhone8,4":                           return "iPhone SE"
        case "iPhone9,1", "iPhone9,3":              return "iPhone 7"
        case "iPhone9,2", "iPhone9,4":              return "iPhone 7 Plus"
        case "iPhone10,1", "iPhone10,4":            return "iPhone 8"
        case "iPhone10,2", "iPhone10,5":            return "iPhone 8 Plus"
        case "iPhone10,3", "iPhone10,6":            return "iPhone X"
        case "iPhone11,8":                          return "iPhone XR"
        case "iPhone11,2":                          return "iPhone XS"
        case "iPhone11,4", "iPhone11,6":            return "iPhone XS Max"
        case "iPhone12,1":                          return "iPhone 11"
        case "iPhone12,3":                          return "iPhone 11 Pro"
        case "iPhone12,5":                          return "iPhone 11 Pro Max"
        case "iPhone12,8":                          return "iPhone SE2"
        case "iPhone13,1":                          return "iPhone 12 mini"
        case "iPhone13,2":                          return "iPhone 12"
        case "iPhone13,3":                          return "iPhone 12 Pro"
        case "iPhone13,4":                          return "iPhone 12 Pro Max"
        case "iPhone14,2":                          return "iPhone 13 Pro"
        case "iPhone14,3":                          return "iPhone 13 Pro Max"
        case "iPhone14,4":                          return "iPhone 13 mini"
        case "iPhone14,5":                          return "iPhone 13"
        case "iPhone14,6":                          return "iPhone SE3"
        case "iPhone14,7":                          return "iPhone 14"
        case "iPhone14,8":                          return "iPhone 14 Plus"
        case "iPhone15,2":                          return "iPhone 14 Pro"
        case "iPhone15,3":                          return "iPhone 14 Pro Max"
        case "iPhone15,4":                          return "iPhone 15"
        case "iPhone15,5":                          return "iPhone 15 Plus"
        case "iPhone16,1":                          return "iPhone 15 Pro"
        case "iPhone16,2":                          return "iPhone 15 Pro Max"
            
        case "i386":                                return "Simulator"
        case "x86_64":                              return "Simulator"
        default:                                    return "unknow"
        }
    }
}
